package merisis.util;

public class LinearArrowSet {

	private BitaSet arrows;

	public LinearArrowSet() {
		this.arrows = new BitaSet();
	}

	public LinearArrowSet(BitaSet arrows) {
		this.arrows = arrows;
	}
	
	public BitaSet getArrows() {
		return arrows;
	}

	public void setArrows(BitaSet arrows) {
		this.arrows = arrows;
	}

	public void set(long src, long dest) {

		// encode the arrow, src -> dest
		long size = 64 - BitUtil.nlz(dest);
		dest <<= size;
		dest |= src;

		arrows.set(dest);
	}

	public boolean unset(long src, long dest) {

		// encode the arrow, src -> dest
		long size = 64 - BitUtil.nlz(dest);
		dest <<= size;
		dest |= src;

		if (!arrows.has(dest))
			return false;

		arrows.unset(dest);

		return true;
	}

	public boolean has(long src, long dest) {

		// encode the arrow, src -> dest
		long nlz = BitUtil.nlz(dest);
		long srcmask = -1L >>> nlz;
		long size = 64 - nlz;
		long arw = (dest << size) | src;
		long max = (dest + 1) << size;

		// Iterate all arrows with the following properties:
		// 1. The destination is the dest.
		// 2. The source succeeds the src.
		BitaSetIterator itr = arrows.iterator(arw);
		long arw1 = itr.next();
		if (arw1 == arw)
			return true;

		for (; arw1 < max && arw1 != -1; arw1 = itr.next()) {

			if (has(src, arw1 & srcmask))
				return true;
		}

		return false;
	}
}
